package com.group9.handinhand.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ValidationUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.group9.handinhand.controller.form.PasswordResetForm;
import com.group9.handinhand.controller.form.ResultViewForm;
import com.group9.handinhand.controller.form.UserRegisterForm;
import com.group9.handinhand.controller.form.UserUpdateForm;
import com.group9.handinhand.dao.model.User;
import com.group9.handinhand.exception.HandInHandException;
import com.group9.handinhand.service.CommunityService;
import com.group9.handinhand.service.EventService;
import com.group9.handinhand.service.MailService;
import com.group9.handinhand.service.OfferService;
import com.group9.handinhand.service.RequestService;
import com.group9.handinhand.service.TagService;
import com.group9.handinhand.service.UserService;
import com.group9.handinhand.service.so.CommunitySO;
import com.group9.handinhand.service.so.PasswordResetLinkSO;
import com.group9.handinhand.service.so.TagSO;
import com.group9.handinhand.service.so.UserEnums.UserStatus;
import com.group9.handinhand.service.so.UserSO;
import com.group9.handinhand.utils.HandInHandWebUtils;

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController extends AbstractBaseController {
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private TagService tagService;
	
	@Autowired
	private EventService eventService;
	
	@Autowired
	private RequestService requestService;
	
	@Autowired
	private CommunityService communityService;
	
	@Autowired
	private OfferService offerService;
	
	@Autowired
	private MailService mailService;
	
	/**
	 * a controller for home page of the site
	 * @param userUpdateForm
	 * @param request
	 * @param response
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/")
	public String home(UserUpdateForm userUpdateForm ,HttpServletRequest request, HttpServletResponse response,  Model model) {	
		UserSO user = getUser();
		if(user != null) {
			userUpdateForm.setUser(user);
			List<TagSO> selectedTags = tagService.getTagsByRelatedUserId(user.getId());
			userUpdateForm.setSelectedTagsFromList(selectedTags);
		}
		
		return "redirect:/user/" + user.getId();
	}
	/**
	 * a controller for login
	 * @param request
	 * @param response
	 * @param model
	 * @return if user exist then login
	 */
	@RequestMapping(value = "/login")
	public String login(HttpServletRequest request, HttpServletResponse response,  Model model) {
		UserSO user = getUser();
		if(user != null) {
			return "redirect:";
		}
		
		return "login";
	}
	/**
	 * a controller for registering to site
	 * @param userRegisterForm
	 * @param errors
	 * @param model
	 * @param request
	 * @param response
	 * @return if no errors, then register
	 */
	@RequestMapping(value = "/register")
	public String register(UserRegisterForm userRegisterForm, BindingResult errors,  Model model, HttpServletRequest request, HttpServletResponse response){
		UserSO currentUser = getUser();
		if(currentUser != null) {
			return "redirect:";
		}
		if(userRegisterForm.getUser() == null){
			userRegisterForm.setUser(new UserSO());
		}
		
		model.addAttribute("errors", errors);
		return "register";
	}
	
	/**
	 * a controller for saving a new user to the database.
	 * @param userRegisterForm
	 * @param errors
	 * @param model
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value = "/saveUser", method = RequestMethod.POST)
	public String saveUser(UserRegisterForm userRegisterForm, BindingResult errors,  Model model, HttpServletRequest request, HttpServletResponse response)  {

		validateNewUser(userRegisterForm, errors);
		
		if (errors.hasErrors()){
			return register(userRegisterForm, errors, model, request, response);
		}
		
		UserSO user = userRegisterForm.getUser();		
		userService.registerUser(user);	
		UserSO registeredUser = userService.getUserByUsername(user.getUsername());
		List<String> selectedTags = userRegisterForm.getSelectedTagsAsList();
		
		tagService.saveUserTags(registeredUser,selectedTags);
		
		authenticateUserAndSetSession(registeredUser, request);
				
		return "redirect:/";
	}
	/**
	 * a controller for forget password.
	 * @param request
	 * @param response
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/forgotPassword", method = RequestMethod.GET)
	public String forgotPassword(HttpServletRequest request, HttpServletResponse response,  Model model) {
		
		return "forgotPassword";
	}
	/**
	 * a controller for forgetting password with post method
	 * gets the email or username of the user
	 * @param request
	 * @param response
	 * @param model
	 * @return 
	 */
	@RequestMapping(value = "/forgotPassword", method = RequestMethod.POST)
	public String forgotPassword2(HttpServletRequest request, HttpServletResponse response,  Model model) {
		
		String emailOrUsername = request.getParameter("emailOrUsername");
		
		String email = mailService.sendForgottenPasswordEmail(emailOrUsername);
		
		model.addAttribute("email", email);
		
		return "forgotPasswordEmailSent";
	}
	/**
	 * a controller for resetting password with get method
	 * @param link
	 * @param passwordResetForm
	 * @param errors
	 * @param request
	 * @param response
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/resetPassword/{link}", method = RequestMethod.GET)
	public String resetPassword(@PathVariable String link, PasswordResetForm passwordResetForm, BindingResult errors, HttpServletRequest request, HttpServletResponse response,  Model model) {
		
		PasswordResetLinkSO passwordResetLink = userService.getPasswordResetLinkByLink(link);
		
		if(passwordResetLink != null) {
			model.addAttribute("link", link);
			return "resetPassword";
		}
			
		return "pageNotFound";
	}
	/**
	 * a controller for resetting password with post method
	 * @param link
	 * @param passwordResetForm
	 * @param errors
	 * @param request
	 * @param response
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/resetPassword/{link}", method = RequestMethod.POST)
	public String resetPassword2(@PathVariable String link, PasswordResetForm passwordResetForm, BindingResult errors, HttpServletRequest request, HttpServletResponse response,  Model model) {
		
		PasswordResetLinkSO passwordResetLink = userService.getPasswordResetLinkByLink(link);
		
		if(passwordResetLink != null) {
			validatePasswordResetForm(passwordResetForm, errors);
			
			if(errors.hasErrors()) {
				return resetPassword(link, passwordResetForm, errors, request, response, model);
			}
			
			UserSO user = passwordResetLink.getUser();
			user.setPassword(passwordResetForm.getPassword());
			userService.updateUser(user);
			
			userService.deletePasswordResetLinksOfUser(user);
			
			return "resetPasswordSuccess";
		}
			
		return "pageNotFound";
	}

	/**
	 * login controller for mobile login
	 * @param request
	 * @param resp
	 * @return
	 */
	@RequestMapping(value = "mobile/login", method = RequestMethod.POST)
	public ResponseEntity<Map<String, Object>> loginMobile(HttpServletRequest request, HttpServletResponse resp) {
		Map<String, Object> response = new HashMap<String, Object>();		

		String username = request.getParameter("username");
		String password = request.getParameter("password");
		

		
		User user = userService.getUserByEmailAndPassword(username, password);
		if (user == null) {
			user = userService.getUserByUsernameAndPassword(username, password);
			if (user == null) {
				throw new HandInHandException("User not found with this username or email address!");
			}
		}
		 
		response.put("user", user.convertToServiceObject());
		response.put("auth", HandInHandWebUtils.generateCookieForUser(user));
		response.put("message", "OK");
		return new ResponseEntity<Map<String, Object>>(response, HttpStatus.OK);
	}
	
	/**
	 * Mobile controller for signing up user
	 * @param request
	 * @param body
	 * @return
	 * @throws JSONException
	 */
	@RequestMapping(value = "mobile/signup", method = RequestMethod.POST)
	public ResponseEntity<Map<String, Object>> signupMobile(HttpServletRequest request, @RequestBody String body) throws JSONException {
		Map<String, Object> response = new HashMap<String, Object>();

		JSONObject json = new JSONObject(body);
		//HandInHandWebUtils.rejectIfEmpty(json, "email", "password", "username");

		String name = json.getString("name");
		String surname = json.getString("surname");
		String username = json.getString("username");
		String email = json.getString("email");
		String password = json.getString("password");
		
		UserSO user = new UserSO();		
		
		user.setName(name);
		user.setSurname(surname);		
		user.setUsername(username);
		user.setEmail(email);		
		user.setPassword(password);
		user.setStatus(UserStatus.ACTIVE);
		
		user = userService.registerUser(user);
		response.put("user", user);
		response.put("auth", HandInHandWebUtils.generateCookieForUser(user.convertToModelObject()));
		response.put("message", "OK");

		return new ResponseEntity<Map<String, Object>>(response, HttpStatus.OK);
	}

	private void validateNewUser(UserRegisterForm userRegisterForm, BindingResult errors) {
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "user.username", "required.field");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "user.name", "required.field");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "user.surname", "required.field");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "user.email", "required.field");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "user.password", "required.field");
//		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "rePassword", "required.field");
		
		UserSO user = userRegisterForm.getUser();
		
		UserSO userExists = userService.getUserByUsername(user.getUsername());
		if(userExists != null) {
			errors.rejectValue("user.username", "username.alreadyexists");
		}
		userExists = userService.getUserByEmail(user.getEmail());
		if(userExists != null) {
			errors.rejectValue("user.email", "email.alreadyregistered");
		}
		if( !user.getPassword().equals(userRegisterForm.getRePassword())){
			errors.rejectValue("rePassword", "passwords.dontmatch");
		}
	}
	/**
	 * a method for validating password
	 * @param passwordResetForm
	 * @param errors
	 */
	private void validatePasswordResetForm(PasswordResetForm passwordResetForm, BindingResult errors) {
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "required.field");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "rePassword", "required.field");
		
		if( !passwordResetForm.getPassword().equals(passwordResetForm.getRePassword())){
			errors.rejectValue("rePassword", "passwords.dontmatch");
		}
	}
	/**
	 * a controller for search
	 * search is according to community, event, request, offer
	 * @param request
	 * @param response
	 * @param resultViewForm
	 * @param model
	 * @return
	 */
	@RequestMapping(value="/search")
	public String search(HttpServletRequest request, HttpServletResponse response,ResultViewForm resultViewForm,  Model model){
		UserSO user = getUser();
		
		String keyword = request.getParameter("search");
		resultViewForm.setKeyword(keyword);
		String selection=request.getParameter("selection");
		resultViewForm.setSelection(selection);

		if (!keyword.isEmpty())
		{		
		ArrayList<Object> searchList = new ArrayList<Object>();
		
		if (selection.equals("user"))
		{
			searchList.add(userService.getUserByUsername(keyword));	
		}
		
		
		if (selection.equals("community"))
		{
		
		searchList.addAll(communityService.getCommunitiesByName(keyword));
		searchList.addAll(communityService.getCommunitiesByTagKeyword(keyword));
		
		
		
		}
		if (selection.equals("events"))
		{
			List<CommunitySO> communityList = communityService.getCommunitiesByUser(user);
			ArrayList<Object> communitysEvents = new ArrayList<Object>();
			model.addAttribute("communityList", communityList);
		
			searchList.addAll(eventService.getEventsByName(keyword));			
			searchList.addAll(eventService.getEventsByTagName(keyword));			
			
			
			for(int i=0;i<communityList.size();i++)	
			{
			communitysEvents.addAll(communityList.get(i).getEvents());			
			}
			
			for(int i=0;i<searchList.size();i++)
			{
				if (!communitysEvents.contains(searchList.get(i)))
						{
					searchList.remove(i);
						}
			}	
			
		}
		if (selection.equals("request"))
		{
			List<CommunitySO> communityList = communityService.getCommunitiesByUser(user);
			ArrayList<Object> communitysRequests = new ArrayList<Object>();
			model.addAttribute("communityList", communityList);
			searchList.addAll(requestService.getRequestsByName(keyword));	
			searchList.addAll(requestService.getRequestsByTagName(keyword));			
		
			for(int i=0;i<communityList.size();i++)	
			{
				communitysRequests.addAll(communityList.get(i).getRequests());			
			}
			
			for(int i=0;i<searchList.size();i++)
			{
				if (!communitysRequests.contains(searchList.get(i)))
						{
					searchList.remove(i);
						}
			}	
			
		}
		if (selection.equals("offer"))
		{
			List<CommunitySO> communityList = communityService.getCommunitiesByUser(user);
			ArrayList<Object> communitysOffers = new ArrayList<Object>();
			model.addAttribute("communityList", communityList);
			searchList.addAll(offerService.getOffersByName(keyword) );	
			searchList.addAll(offerService.getOffersByTagName(keyword) );			
		
			for(int i=0;i<communityList.size();i++)	
			{
				communitysOffers.addAll(communityList.get(i).getOffers());			
			}
			
			for(int i=0;i<searchList.size();i++)
			{
				if (!communitysOffers.contains(searchList.get(i)))
						{
					searchList.remove(i);
						}
			}	
			
		}
		

		for(int i=0;i<searchList.size();i++)
		{
			for (int j=i+1;j<searchList.size();j++)
			{
			if (searchList.get(i).equals(searchList.get(j)))
			{
				searchList.remove(j);
			}	
			}	
		}
		int isEmptyResult=0;
		if (searchList.isEmpty())
		{
			isEmptyResult=1;
		}
		resultViewForm.setIsEmptyResult(isEmptyResult);
		resultViewForm.setSearchList(searchList);
		
		return "searchResults";
		}
		return"pageNotFound";
	}
}
